#include "CassiopeiaMain.h"

CassiopeiaMain* CassiopeiaMain::instance = 0;
UINT CassiopeiaMain::WM_TASKBARCREATED = 0;

CassiopeiaMain::CassiopeiaMain(HINSTANCE hInstance)
{
	hWnd = 0;

	if (!WM_TASKBARCREATED)
		WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated"));

	closed = false;
	this->hInstance = hInstance;

	OSVERSIONINFO osvi={0};
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);

	if (osvi.dwMajorVersion < 6)
		dwmEnabled = FALSE;
	else
		DwmIsCompositionEnabled(&dwmEnabled);

	LPCWSTR className=TEXT("CassiopeiaMainWindow");

	WNDCLASSEX wndClass={0};
	wndClass.cbSize=sizeof(wndClass);
	wndClass.lpfnWndProc=WndProc;
	wndClass.hInstance=hInstance;
	wndClass.lpszClassName=className;
	RegisterClassEx(&wndClass);

	hWnd=CreateWindowEx(0,className,0,0,20,20,200,200,0,0,hInstance,0);

	instance = this;

	InitTrayMenu();
	StartComponents(hInstance);
}

CassiopeiaMain::~CassiopeiaMain()
{	
	Close();
}

CassiopeiaMain* CassiopeiaMain::CreateInstance(HINSTANCE hInstance)
{
	if (instance)
		return 0;

	return new CassiopeiaMain(hInstance);
}


bool CassiopeiaMain::Close()
{
	return Close(true);
}

bool CassiopeiaMain::Close(bool postQuitMsg)
{
	if (closed)
		return true;	

	if (!StopComponents())
		return false;

	closed=true;

	Shell_NotifyIcon(NIM_DELETE, &notifyIconData);
	DestroyWindow(hWnd);
	DestroyMenu(trayMenu);

	instance = 0;

	if (postQuitMsg)
		PostQuitMessage(0);

	return true;
}


void CassiopeiaMain::InitTrayMenu()
{
	notifyIconData.cbSize=sizeof(NOTIFYICONDATA);
	notifyIconData.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
	notifyIconData.uID=42;
	notifyIconData.uVersion=NOTIFYICON_VERSION_4;
	notifyIconData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
	_tcscpy(notifyIconData.szTip,TEXT("Cassiopeia"));
	notifyIconData.hWnd = hWnd;
	notifyIconData.uCallbackMessage = WM_APP+1;
	Shell_NotifyIcon(NIM_ADD, &notifyIconData);

	HMENU subMenu = 0;

	trayMenu = CreatePopupMenu();
	AppendMenu(trayMenu, MF_STRING, TrayMenu_AdvancedShowDesktop, TEXT("Advanced ShowDesktop"));
	AppendMenu(trayMenu, MF_STRING, TrayMenu_DeskNotes, TEXT("DeskNotes"));
	AppendMenu(trayMenu, MF_STRING, TrayMenu_DeskTidy, TEXT("DeskTidy"));
	AppendMenu(trayMenu, MF_STRING, TrayMenu_WindowTools, TEXT("Window Tools"));

	subMenu=CreatePopupMenu();
	AppendMenu(subMenu, MF_STRING, TrayMenu_SchedulerActive, TEXT("Active"));
	AppendMenu(subMenu, MF_SEPARATOR, TrayMenu_Separator1, 0);
	AppendMenu(subMenu, MF_STRING, TrayMenu_SchedulerSetAlert, TEXT("Set Alert...\tWin+S"));
	SetMenuDefaultItem(subMenu, TrayMenu_SchedulerActive, 0);
	AppendMenu(trayMenu, MF_STRING | MF_POPUP,(UINT_PTR)subMenu, TEXT("Scheduler"));

	AppendMenu(trayMenu, MF_STRING, TrayMenu_DesktopPictureFrame, TEXT("Desktop Picture Frame"));
	AppendMenu(trayMenu, MF_SEPARATOR, TrayMenu_Separator5, 0);

	subMenu=CreatePopupMenu();
	AppendMenu(subMenu, MF_STRING, TrayMenu_WindowsMinimizeAll, TEXT("Minimize All"));
	AppendMenu(subMenu, MF_STRING, TrayMenu_WindowsRestoreAll, TEXT("Restore All"));
	AppendMenu(trayMenu, MF_STRING | MF_POPUP,(UINT_PTR)subMenu, TEXT("Windows"));

	set<TCHAR> drives = Utilities::GetDrives(DRIVE_CDROM);
	if (!drives.empty())
	{
		subMenu = CreatePopupMenu();
		int counter = 0;
		set<TCHAR>::iterator iter;
		for (iter = drives.begin(); iter != drives.end(); iter++)
		{
			TCHAR drive[] = {*iter, ':', '\0'};
			AppendMenu(subMenu, MF_STRING, TrayMenu_LockDrivesFirstID + counter++, drive);
		}

		AppendMenu(trayMenu, MF_STRING | MF_POPUP, (UINT_PTR)subMenu, TEXT("Lock Drives"));
	}

	AppendMenu(trayMenu,MF_SEPARATOR, TrayMenu_Separator7, 0);


	AppendMenu(trayMenu,MF_STRING, TrayMenu_Close, TEXT("Exit"));
	SetMenuDefaultItem(trayMenu, TrayMenu_Close, 0);
}

void CassiopeiaMain::StartComponents(HINSTANCE hInstance)
{
	Settings settings;
	Settings::Data data={0};
	data.CassiopeiaMainData.DeskNotes = true;
	data.CassiopeiaMainData.Scheduler = true;
	data.CassiopeiaMainData.AdvancedShowDesktop = true;
	data.CassiopeiaMainData.DeskTidy = false;
	data.CassiopeiaMainData.DesktopPictureFrame = false;
	data.CassiopeiaMainData.WindowTools = true;
	settings.Load(&data);

	scheduler = new Scheduler(hInstance);
	scheduler->ActiveChanged(SchedulerActiveChanged);
	if (data.CassiopeiaMainData.Scheduler)
		scheduler->Activate();
	else
		EnableMenuItem(trayMenu,TrayMenu_SchedulerSetAlert,MF_DISABLED);


	deskNotes = new DeskNotes();
	deskNotes->Create(hInstance);
	deskNotes->ActiveChanged(DeskNotesActiveChanged);
	if (data.CassiopeiaMainData.DeskNotes)
		deskNotes->Activate();


	advancedShowDesktop = AdvancedShowDesktop::CreateInstance(hInstance);
	advancedShowDesktop->ActiveChanged(AdvancedShowDesktopActiveChanged);
	if (data.CassiopeiaMainData.AdvancedShowDesktop)
		advancedShowDesktop->Activate();


	deskTidy = DeskTidy::CreateInstance(hInstance);
	deskTidy->ActiveChanged(DeskTidyActiveChanged);
	if (data.CassiopeiaMainData.DeskTidy)
		deskTidy->Activate();


	desktopPictureFrame = new DesktopPictureFrame();
	desktopPictureFrame->Create(hInstance);
	desktopPictureFrame->ActiveChanged(desktopPictureFrame_ActiveChanged);
	if (data.CassiopeiaMainData.DesktopPictureFrame)
		desktopPictureFrame->Activate();

	windowTools = WindowTools::CreateInstance(hInstance);
	windowTools->ActiveChanged(WindowToolsActiveChanged);
	if (data.CassiopeiaMainData.WindowTools)
		windowTools->Activate();
}

bool CassiopeiaMain::StopComponents()
{
	Settings settings;
	Settings::Data data = {0};
	settings.Load(&data);
	data.CassiopeiaMainData.DeskNotes = deskNotes->IsActive();
	data.CassiopeiaMainData.Scheduler = scheduler->IsActive();
	data.CassiopeiaMainData.AdvancedShowDesktop = advancedShowDesktop->IsActive();
	data.CassiopeiaMainData.DeskTidy = deskTidy->IsActive();
	data.CassiopeiaMainData.DesktopPictureFrame = desktopPictureFrame->IsActive();
	data.CassiopeiaMainData.WindowTools = windowTools->IsActive();
	settings.Save(data);

	if (deskNotes->Deactivate() == CCState::NotReady)
		return false;	

	delete scheduler;
	scheduler=0;

	delete deskNotes;
	deskNotes=0;

	delete advancedShowDesktop;
	advancedShowDesktop=0;

	delete deskTidy;
	deskTidy=0;

	delete desktopPictureFrame;
	desktopPictureFrame = 0;

	delete windowTools;
	windowTools = 0;

	//unlock all drives
	set<TCHAR> drives = Utilities::GetDrives();
	if (!drives.empty())
	{
		set<TCHAR>::iterator iter;
		for (iter = drives.begin(); iter != drives.end(); iter++)
		{
			Utilities::LockDrive(*iter, false);
		}
	}

	return true;
}


void CassiopeiaMain::WindowToolsActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu, TrayMenu_WindowTools, active ? MF_CHECKED : MF_UNCHECKED);
}

void CassiopeiaMain::desktopPictureFrame_ActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu, TrayMenu_DesktopPictureFrame, active ? MF_CHECKED : MF_UNCHECKED);
}

void CassiopeiaMain::DeskTidyActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu,TrayMenu_DeskTidy,active?MF_CHECKED:MF_UNCHECKED);
}

void CassiopeiaMain::AdvancedShowDesktopActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu,TrayMenu_AdvancedShowDesktop,active?MF_CHECKED:MF_UNCHECKED);
}

void CassiopeiaMain::DeskNotesActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu,TrayMenu_DeskNotes,active?MF_CHECKED:MF_UNCHECKED);
}

void CassiopeiaMain::SchedulerActiveChanged(CassiopeiaComponent* sender, bool active)
{
	CheckMenuItem(instance->trayMenu,TrayMenu_SchedulerActive,active?MF_CHECKED:MF_UNCHECKED);
	EnableMenuItem(instance->trayMenu,TrayMenu_SchedulerSetAlert,active?MF_ENABLED:MF_DISABLED);
}


LRESULT CALLBACK CassiopeiaMain::WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	if (uMsg == WM_TASKBARCREATED)
		Shell_NotifyIcon(NIM_ADD, &instance->notifyIconData);

	switch (uMsg)
	{	
	case WM_DWMCOMPOSITIONCHANGED:
		{
			DwmIsCompositionEnabled(&instance->dwmEnabled);
			break;
		}
	case WM_COMMAND:
		{
			if (LOWORD(wParam) >= TrayMenu_LockDrivesFirstID && LOWORD(wParam) <= TrayMenu_LockDrivesLastID)
			{
				int menuID = LOWORD(wParam);
				TCHAR driveString[10] = {0};
				GetMenuString(instance->trayMenu, menuID, driveString, 10, 0);
				TCHAR drive = driveString[0];

				if (GetMenuState(instance->trayMenu, menuID, 0) & MF_CHECKED)
				{
					if (Utilities::LockDrive(drive, false))
						CheckMenuItem(instance->trayMenu, menuID, MF_UNCHECKED);
				}
				else
				{
					if (Utilities::LockDrive(drive, true))
						CheckMenuItem(instance->trayMenu, menuID, MF_CHECKED);
				}
			}
			else
			{
				switch (LOWORD(wParam))
				{
				case TrayMenu_AdvancedShowDesktop:
					{
						instance->advancedShowDesktop->ToggleActiveState();
						break;
					}
				case TrayMenu_DeskNotes:
					{
						instance->deskNotes->ToggleActiveState();
						break;
					}
				case TrayMenu_DeskTidy:
					{
						instance->deskTidy->ToggleActiveState();
						break;
					}		
				case TrayMenu_WindowTools:
					{
						instance->windowTools->ToggleActiveState();
						break;
					}	
				case TrayMenu_SchedulerActive:
					{
						instance->scheduler->ToggleActiveState();
						break;
					}
				case TrayMenu_SchedulerSetAlert:
					{
						instance->scheduler->SetAlert();
						break;
					}
				case TrayMenu_DesktopPictureFrame:
					{
						instance->desktopPictureFrame->ToggleActiveState();
						break;
					}
				case TrayMenu_WindowsMinimizeAll:
					{
						EnumWindows(EnumWindowsProc,TrayMenu_WindowsMinimizeAll);
						break;
					}
				case TrayMenu_WindowsRestoreAll:
					{
						EnumWindows(EnumWindowsProc,TrayMenu_WindowsRestoreAll);
						break;
					}
				case TrayMenu_Close:
					{
						instance->Close();
						break;
					}
				}
			}
			break;
		}
	case WM_APP+1:
		{
			switch(LOWORD(lParam))
			{
			case WM_RBUTTONDOWN:
			case WM_CONTEXTMENU:
				{
					POINT cursorPos=Utilities::GetCursorPosition();
					SetForegroundWindow(hWnd);
					TrackPopupMenu(instance->trayMenu, TPM_VERPOSANIMATION | TPM_LEFTBUTTON, cursorPos.x, cursorPos.y, 0, hWnd, 0);
					PostMessage(hWnd, WM_NULL, 0, 0);
					break;
				}
			case WM_LBUTTONDBLCLK:
				{
					instance->Close();
					break;
				}
			}

			break;
		}
	case WM_QUERYENDSESSION:
		{
			if (!instance->Close(false))
				return FALSE;
			else
				return TRUE;
		}
	case WM_DESTROY:	
		{
			instance->Close();
			break;
		}
	}

	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

BOOL CALLBACK CassiopeiaMain::EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
	if (IsWindow(hWnd)
		&& IsWindowVisible(hWnd)
		&& !Utilities::IsSpecialWindow(hWnd))
	{
		switch (lParam)
		{
		case TrayMenu_WindowsRestoreAll:
			{
				if (IsWindowEnabled(hWnd) && !Utilities::IsSpecialCassiopeiaWindow(hWnd) && IsIconic(hWnd) && !IsZoomed(hWnd))
					ShowWindow(hWnd,SW_RESTORE);

				//WindowRestore
				if (IsWindowEnabled(hWnd) && !IsIconic(hWnd) && !IsZoomed(hWnd))
					Utilities::MoveWindowIntoVisibleArea(hWnd);
				break;
			}
		case TrayMenu_WindowsMinimizeAll:
			{
				if (IsWindowEnabled(hWnd) && !IsIconic(hWnd) && !Utilities::IsSpecialCassiopeiaWindow(hWnd))
					ShowWindow(hWnd,SW_MINIMIZE);
				
				break;
			}
		}
	}

	return true;
}
